#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ide.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <asm/unaligned.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/atomic.h>
#include <linux/poll.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>

#define gt911_NAME  "gt911"
#define gt911_CNT   1

#define GT_CTRL_REG 0X8040
#define GT_MODESW_REG 0X804D
#define GT_9xx_CFGS_REG 0X8047
#define GT_1xx_CFGS_REG 0X8050
#define GT_CHECK_REG 0X80FF
#define GT_PID_REG  0X8140

#define GT_GSTID_REG 0X814E
#define GT_TP1_REG   0X814F
#define GT_TP2_REG   0X8157
#define GT_TP3_REG   0X815E
#define GT_TP4_REG   0X8167
#define GT_TP5_REG   0X816F
#define MAX_SUPPORT_POINTS 5


struct gt911_dev{
  /********** 保留核心硬件资源（仅触摸必需）**********/
    int irqnum;                 // 中断号（触摸触发核心）​
    int irqtype;                // 中断类型（上升沿/下降沿等）​
    int irq_pin, reset_pin;     // 中断/复位引脚（硬件初始化必需）​

    /********** 保留核心功能对象（不可删除）**********/
    struct input_dev *input;    // input子系统对象（触摸数据上报）​
    struct regmap *regmap;      // regmap对象（寄存器操作核心）​
    struct regmap_config regcfg;// 简化命名：regmap配置（原regmap_config）​

    /********** 保留功能参数（不可删除）**********/
    int max_x, max_y;           // 触摸屏分辨率（input配置必需）​
    struct i2c_client *client;  // 直接存i2c_client，替代
};

const u8 irq_table[] = {IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_LEVEL_LOW,IRQ_TYPE_LEVEL_HIGH};


static unsigned char gt911_read_reg(struct gt911_dev *dev, u16 reg)
{
    u8 ret;
    unsigned int data;

    ret = regmap_read(dev->regmap,reg,&data);
    return (u8)data;
}

static uint8_t gt911_read_regs(struct gt911_dev *dev, u16 start_reg, u8 *buf, int n)
{
    int ret;

    // 调用regmap_bulk_read：
    // 1. 先传输16位起始地址（拆成2字节）；
    // 2. 连续读取n个字节（每个字节对应一个8位寄存器）
    ret = regmap_bulk_read(dev->regmap, start_reg, buf, n);
    if (ret != 0) {
        dev_err(&dev->client->dev, "Bulk read from 0x%04x failed (ret=%d, n=%d)\n", 
                start_reg, ret, n);
        return 1; // 返回错误码，供上层处理
    }

    return 0; // 成功返回0
}

static void gt911_write_regs(struct gt911_dev* dev, u16 reg, u8 value)
{
    regmap_write(dev->regmap,reg,value);
}

static irqreturn_t gt911_irq_handle(int irq, void *dev_id)
{
    struct gt911_dev *dev = dev_id;
    u8 data;
    u8 touch_data[5];
    int touch_num, id, input_x, input_y;

    data = gt911_read_reg(dev, GT_GSTID_REG);
    if ((data & 0x0F) == 0) { 
        input_mt_slot(dev->input, 0);
        input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, false);
        input_sync(dev->input);
        gt911_write_regs(dev, GT_GSTID_REG, 0x00); 
        return IRQ_HANDLED;
    }
    /********** 优化2：减少判断分支，直接解析触摸点（提升速度）**********/
    touch_num = data & 0x0F; // 提取触摸点数量（仅低4位有效）​
    if (touch_num > MAX_SUPPORT_POINTS) {
        touch_num = MAX_SUPPORT_POINTS; // 限制最大触摸点，避免数组越界​
    }
      /********** 优化3：仅处理第一个触摸点（原代码是单点触摸，简化逻辑）**********/
    // 读第一个触摸点数据（GT_TP1_REG）：用gt911_read_regs，直接传数组​
    if (gt911_read_regs(dev, GT_TP1_REG, touch_data, 5) != 0) {
        goto fail; // 读失败，直接清理​
    }

    id = touch_data[0] & 0x0F; // 提取触摸点ID（低4位有效）​
    if (id != 0) {
        goto fail; // 只处理ID=0的触摸点（原代码逻辑，简化判断）​
    }

     /********** 优化4：直接解析坐标，减少类型转换（提升速度）**********/
    input_x = (touch_data[2] << 8) | touch_data[1]; // 高8位+低8位（GT911坐标格式）​
    input_y = (touch_data[4] << 8) | touch_data[3];

     /********** 优化5：减少冗余的input调用，直接上报（提升速度）**********/
    input_mt_slot(dev->input, id);
    input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, true);
    input_report_abs(dev->input, ABS_MT_POSITION_X, input_x);
    input_report_abs(dev->input, ABS_MT_POSITION_Y, input_y);
    input_mt_report_pointer_emulation(dev->input, true);
    input_sync(dev->input);

    fail:
     /********** 优化6：统一清理触摸状态，避免重复代码（提升速度）**********/
    gt911_write_regs(dev, GT_GSTID_REG, 0x00);
    return IRQ_HANDLED;
}


static int gt911_read_firmware(struct i2c_client *client, struct gt911_dev *dev)
{
    int ret = 0, version = 0;
    u16 id = 0;
    u8 data[7] = {0};
    char id_str[5];
    ret = gt911_read_regs(dev,GT_PID_REG,data,6);
    if(ret)
    {
        dev_err(&client->dev,"Unable to read PID.\n");
        return ret;
    }
    memcpy(id_str,data,4);
    id_str[4] = 0;
    if(kstrtou16(id_str,10,&id))
        id = 0x1001;
    version = get_unaligned_le16(&data[4]);
    dev_info(&client->dev,"ID %d, version: %04x\n",id,version);
    switch(id){
        case 1151:
        case 1158:
        case 5663:
        case 5688:
            ret = gt911_read_regs(dev,GT_1xx_CFGS_REG,data,7);
            break;
        default:
            ret = gt911_read_regs(dev,GT_9xx_CFGS_REG,data,7);
            break;
    }
    if(ret)
    {
        dev_err(&client->dev,"Unable to read Firmware.\n");
        return ret;
    }
    dev->max_x = (data[2] << 8) + data[1];
    dev->max_y = (data[4] << 8) + data[3];

    dev->irqtype = data[6] & 0x03;

    printk("X_MAX: %d, Y_MAX: %d, TRIGGER: 0X%02x",dev->max_x,dev->max_y,dev->irqtype);

    return 0;
}


static int gt911_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
    u8 data = 0x02;

    struct gt911_dev *gt911dev = devm_kzalloc(&client->dev,sizeof(*gt911dev),GFP_KERNEL);
    if(!gt911dev){
        printk("分配内存失败\r\n");
        return -ENOMEM;
    }

    gt911dev->client = client;
    i2c_set_clientdata(client, gt911dev); // 绑定客户端数据

    gt911dev->regcfg= (struct regmap_config){
        .reg_bits = 16,                  // 16位地址（GT911必需）​
        .val_bits = 8,                   // 8位数据（GT911寄存器是8位）​
        .reg_format_endian = REGMAP_ENDIAN_BIG, // 地址先传高8位（GT911要求）​
    };
    
    /* 初始化IIC接口的regmap */
	gt911dev->regmap = regmap_init_i2c(client, &gt911dev->regcfg);
	if (IS_ERR(gt911dev->regmap)) {
        printk("regmap_init failed!\r\n");
        ret = PTR_ERR(gt911dev->regmap);
        goto fail_mem; // 跳转到内存释放
	}	
    printk("the driver is compatible to the device!\r\n");


    // 解析复位引脚
    gt911dev->reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
    if (gt911dev->reset_pin < 0) {
        dev_err(&client->dev, "parse reset-gpios failed\n");
        ret = gt911dev->reset_pin;
        goto fail_regmap;
    }
    // 申请复位引脚（devm_在低内核可用，自动回收）
    ret = devm_gpio_request_one(&client->dev, 
                                gt911dev->reset_pin, 
                                GPIOF_OUT_INIT_HIGH, 
                                "gt911 reset");
    if (ret) {
        dev_err(&client->dev, "request reset-gpios failed\n");
        goto fail_regmap;
    }

    // 解析中断引脚
    gt911dev->irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);
    if (gt911dev->irq_pin < 0) {
        dev_err(&client->dev, "parse interrupt-gpios failed\n");
        ret = gt911dev->irq_pin;
        goto fail_regmap;
    }
   
    ret = devm_gpio_request_one(&client->dev, 
                                gt911dev->irq_pin, 
                                GPIOF_OUT_INIT_HIGH, 
                                "gt911 int");
    if (ret) {
        dev_err(&client->dev, "request interrupt-gpios failed\n");
        goto fail_regmap;
    }


    gpio_set_value(gt911dev->reset_pin,0);
    msleep(10);
    gpio_set_value(gt911dev->reset_pin,1);
    msleep(10);
    gpio_set_value(gt911dev->irq_pin,0);
    msleep(50);
    gpio_direction_input(gt911dev->irq_pin);


    // 配置IRQ引脚：直接设置方向，减少重复赋值（原先置0再设输入，合并为1步）
    gpio_set_value(gt911dev->irq_pin, 0);
    usleep_range(50000, 51000); // 50ms延时（按手册最小要求）​
    gpio_direction_input(gt911dev->irq_pin);

    /********** 优化复位逻辑：减少冗余GPIO操作，缩短延时（提升速度）**********/
    // 复位GT911：按手册最小延时（原10ms→5ms，不影响稳定性，减少等待）
    gt911_write_regs(gt911dev,GT_CTRL_REG,0x02);
    mdelay(100);
    data = 0x0;
    gt911_write_regs(gt911dev,GT_CTRL_REG,0x00);
    mdelay(100);

    //初始化gt911 读取固件
    ret = gt911_read_firmware(client,gt911dev);
    if(ret != 0){
        printk("Fail !!! check !!\r\n");
        goto fail_regmap;
    }

    //初始化input设备
    gt911dev->input = devm_input_allocate_device(&client->dev);
    if (!gt911dev->input) {
        dev_err(&client->dev, "input allocate failed\n");
        return -ENOMEM;
        goto fail_regmap;
    }

    //配置input设备
    gt911dev->input->name = client->name;
    gt911dev->input->id.bustype = BUS_I2C;
    gt911dev->input->dev.parent = &client->dev;

    input_set_capability(gt911dev->input, EV_KEY, BTN_TOUCH);
    input_set_capability(gt911dev->input, EV_ABS, ABS_X);
    input_set_capability(gt911dev->input, EV_ABS, ABS_Y);
    input_set_capability(gt911dev->input, EV_ABS, ABS_MT_POSITION_X);
    input_set_capability(gt911dev->input, EV_ABS, ABS_MT_POSITION_Y);

    input_set_abs_params(gt911dev->input,ABS_X,0,gt911dev->max_x,0,0);
    input_set_abs_params(gt911dev->input,ABS_Y,0,gt911dev->max_y,0,0);
    input_set_abs_params(gt911dev->input,ABS_MT_POSITION_X,0,gt911dev->max_x,0,0);
    input_set_abs_params(gt911dev->input,ABS_MT_POSITION_Y,0,gt911dev->max_y,0,0);

    ret = input_mt_init_slots(gt911dev->input,MAX_SUPPORT_POINTS,0);
    if(ret){
        goto fail_input;
    }

  // 注册input设备
    ret = input_register_device(gt911dev->input);
    if (ret) {
        goto fail_input;
    }

    // 解析中断号
    gt911dev->irqnum = irq_of_parse_and_map(client->dev.of_node, 0);
    if (gt911dev->irqnum <= 0) {
        dev_err(&client->dev, "parse irqnum failed\n");
        ret = -EINVAL;
        goto fail_input_reg;
    }

    // 注册中断
    ret = request_threaded_irq(gt911dev->irqnum, NULL,
                              gt911_irq_handle,
                              irq_table[gt911dev->irqtype] | IRQF_ONESHOT,
                              client->name, gt911dev);
    if (ret) {
        dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
        goto fail_irq;
    }

    dev_info(&client->dev, "gt911 probe success (max_x:%d, max_y:%d)\n", 
             gt911dev->max_x, gt911dev->max_y);
    
    return 0;

    
fail_irq:
    irq_dispose_mapping(gt911dev->irqnum);
fail_input_reg:
    input_unregister_device(gt911dev->input);
    gt911dev->input = NULL; // 防止double free
fail_input:
    input_free_device(gt911dev->input);
fail_regmap:
    regmap_exit(gt911dev->regmap);
fail_mem:
    return ret;
}

static int gt911_remove(struct i2c_client *client)
{
    struct gt911_dev *gt911dev = i2c_get_clientdata(client);
    
    // 1. 释放中断资源（中断号有效时）
    if (gt911dev->irqnum > 0) {
        free_irq(gt911dev->irqnum, gt911dev);       // 释放中断
        irq_dispose_mapping(gt911dev->irqnum);       // 清理中断映射
        gt911dev->irqnum = 0;                        // 避免重复释放
    }
    
    // 2. 释放input子系统资源
    if (gt911dev->input) {
        input_unregister_device(gt911dev->input);    // 注销input设备
        input_free_device(gt911dev->input);          // 释放input设备内存
        gt911dev->input = NULL;                      // 避免野指针
    }
    
    // 3. 释放regmap资源（regmap有效时）
    if (gt911dev->regmap && !IS_ERR(gt911dev->regmap)) {
        regmap_exit(gt911dev->regmap);               // 退出regmap
        gt911dev->regmap = NULL;                     // 避免野指针
    }
    
    dev_info(&client->dev, "gt911 device removed completely\n");
    return 0;
}

/* 传统匹配方式ID列表 */
static const struct i2c_device_id gt911_id[] = {
	{"gary,gt911", 0},  
	{}
};

//device-tree
static const struct of_device_id gt911_of_match[]={
    {.compatible = "gary,gt911"},
    {}              
};

static struct i2c_driver gt911_driver = {
    .probe = gt911_probe,
    .remove = gt911_remove,
    .driver = {
        .owner = THIS_MODULE,
        .of_match_table = gt911_of_match,
        .name = "gt911",
    },
    .id_table = gt911_id,
};

static int __init gt911driver_init(void)
{
    int ret = 0;
    ret = i2c_add_driver(&gt911_driver);
    return ret;
}

static void __exit gt911driver_exit(void)
{
    i2c_del_driver(&gt911_driver);
}


module_init(gt911driver_init);
module_exit(gt911driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GARY");